import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';
import { MysqlService, DBConfig } from 'src/app/service/mysql.service';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NzTreeNode, NzTreeNodeOptions, NzMessageService, NzNotificationService, NzTreeComponent } from 'ng-zorro-antd';
import { debounceTime } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { MessageService } from 'primeng/api';


@Component({
  selector: 'app-dbmanager',
  templateUrl: './dbmanager.component.html',
  styleUrls: ['./dbmanager.component.css']
})
export class DbmanagerComponent implements OnInit {

  drawerVisible:boolean = false;
  validateForm:FormGroup;
  singleControllerForm:FormGroup;
  preSuffixJavaModelForm:FormGroup;// 生成带有前后缀的 Java Model
  preSuffixAngularModelForm:FormGroup;// 生成带有前后缀的 Angular Model
  preSuffixMybatisResultMapForm:FormGroup;
  chroRptServiceForm:FormGroup;
  chroRptControllerForm:FormGroup;
  insertTableStyleForm:FormGroup;

  treeData:any[] = [];
  dbConfig:DBConfig;

  selectedNode:NzTreeNode;
  expandNode:NzTreeNode;

  searchValue:string;
  delayedSearchValue:string;

  hideUnMatched:boolean = true;// 搜索时隐藏不匹配的项

  fields = [];// 选中表的字段列表

  @ViewChild('tree',{static:false})
  tree:NzTreeComponent;

  searchInput$ = new Subject();
  angularModel:string = "";

  popOverVisible_createMybatisSaveOne:boolean = false;
  popOverVisible_createSpringService:boolean = false;
  popOverVisible_createSpringServiceImpl:boolean = false;
  packagePath_createMybatisSaveOne:string = 'com.ccsoft.femis.model.ContactType';
  drawerVisible_chroRptService:boolean = false;
  drawerVisible_chroRptController:boolean = false;

  popOverVisible_createSpringDao:boolean = false;
  modelName_createSpringDao:string = 'SimpleBasedata';

  popOverVisible_createSpringController:boolean = false;
  modelName_createSpringController:string = 'SimpleBasedata';

  upperAttribute:boolean = false;

  visible_SingleControllerForm:boolean = false;
  modelName_CreateSpringService:string = '';
  modelName_CreateSpringServiceImpl:string = '';


  visible_CreateSQL_pks2Records:boolean = false;
  pks2RecordsForm:FormGroup;

  spanMenuTool:number = 4;//主菜单按钮在 zorro 布局中的宽度


  // 抽屉组件中表单控件以及其CAPTION的宽度 - 生成单表控制器需要的参数
  CAPTION_WIDTH01:number = 9;
  CONTROL_WIDTH01:number = 14;

  drawerVisible_preSuffixJavaModel:boolean = false;// 生成带有前后缀的 Java Model 类的参数设置的抽屉
  drawerVisible_angularModel:boolean =false; // 生成带有前后缀的 Angular Model 类的参数设置的抽屉
  drawerVisible_MybatisResultMap:boolean = false; // 生成带有前后缀的 Mybatis Result Map
  drawerVisible_insertTableStyle:boolean = false; // 生成SQL语句：向表 table_style 插入一个表的所有字段的数据

  modalVisible_charSet:boolean = false;
  modalVisible_emptyString:boolean = false;
  dbNameCharSet = 'gsms';
  dbNameEmptyString = 'gsms';

  constructor(
    private mysqlService:MysqlService,
    private fb:FormBuilder,
    private noti:NzNotificationService,
    private pMsgService:MessageService,
  ) {
    // 打开页面直接请求默认服务器数据
    let db:DBConfig = new DBConfig();
    db.server = '49.234.149.119';
    db.port = 3306;
    db.dbName = 'mysql';
    db.dbUserName = 'root';
    db.dbUserPwd = '!Xdf123456';

    this.connectDB(db);
  }

  ngOnInit() {
    // 生成SQL字符串 - 根据主键字符串查询记录集
    this.pks2RecordsForm = this.fb.group({
      tableName:[null,Validators.required],
      pkFieldName:[null,Validators.required]
    })

    // 初始化表单
    this.validateForm = this.fb.group({
      server:['49.234.149.119',Validators.required],
      port:['3306',Validators.required],
      userName:['root',Validators.required],
      password:['!Xdf123456',Validators.required]
    });

    // 单表控制器代码
    this.singleControllerForm = this.fb.group({
      tableName:[null,Validators.required],
      modelName:[null,Validators.required],
      detailService:[null,Validators.required],
      packageName:[null,Validators.required]
    });

    this.searchInput$.pipe(debounceTime(700)).subscribe(
      (val:string)=>this.delayedSearchValue = val
    )

    // 生成带有前后缀的 Java Model
    this.preSuffixJavaModelForm = this.fb.group({
      prefix:[null],
      suffix:[null]
    })

    // 生成带有前后缀的 Angular Model
    this.preSuffixAngularModelForm = this.fb.group({
      prefix:[null],
      suffix:[null]
    })

    this.preSuffixMybatisResultMapForm = this.fb.group({
      prefix:[null],
      suffix:[null]
    })

    // 生成单据序时表必要的参数表单
    this.chroRptServiceForm = this.fb.group({
      jControllerName:[null],
      mainTableName:[null],
      detailTableName:[null],
      billName:[null],
      mainPrefix:[null],
      detailPrefix:[null]
    })

    // 生成单据序时表控制器代码
    this.chroRptControllerForm = this.fb.group({
      serviceName:[null],
      billModel:[null]
    })

    // 设置参数用的抽屉组件 - 向表 table_style 插入数据的SQL语句
    this.insertTableStyleForm = this.fb.group({
      dbName:['gsms'],
      tableName:[null]
    })


  }

  connectServer(){
    this.drawerVisible = !this.drawerVisible;
  }

  closeDrawer(e){
    this.drawerVisible = false;
  }

  connectDB(dbConfig?:DBConfig){
    if( dbConfig )
      this.dbConfig = dbConfig;
    else
      this.dbConfig = this.getDbConfig();// 将抽屉中的表单数据转换为对象

    this.drawerVisible = false;// 关闭抽屉

    this.mysqlService.buildFieldTree(this.dbConfig).subscribe(
      ( res:any[] )=>{
        console.log(res);
        this.treeData = res;
      },error=>this.msg('构建树时出错！')
    )

  }

  getDbConfig():DBConfig{
    let config = new DBConfig();
    config = new DBConfig();
    config.server = this.validateForm.value["server"];
    config.port = this.validateForm.value["port"];
    config.dbName = "mysql";
    config.dbUserName = this.validateForm.value["userName"];
    config.dbUserPwd = this.validateForm.value["password"];

    return config;
  }

  buildTree(nodes:any[]){
    if( nodes.length<=0 ) return;
    nodes.forEach(ele => {
      let node = {'title':ele.SCHEMA_NAME,'key':ele.SCHEMA_NAME};
      console.log(ele.SCHEMA_NAME + '-' + ele.DEFAULT_CHARACTER_SET_NAME);

      // this.treeData.push(node);
      this.treeData = this.treeData.concat(node);
    });
  }

  submitForm(){
    this.connectDB();
  }

  getTables(dbName:string){
    if(this.dbConfig === null){
      this.noti.blank('通知','还没有链接数据库！');
      return;
    }

    if(this.selectedNode === null){
      this.noti.blank('通知','没有选中节点！');
      return;
    }

    this.mysqlService.getTables(this.dbConfig,dbName).subscribe(
      ( res:any[] )=>{
        console.log(res);

        // 构建表名构成的数组
        let nodes = [];
        res.forEach(ele => {
          nodes.push({'title':ele.table_name + ',' + ele.table_comment,'key':ele.table_name});
        });

        // 将表名数组拼接到树形结构中的指定数据库名下

      },error=>this.msg('获取所有表时出错！')
    )
  }

  // msg(content:string){
  //   this.noti.blank('通知',content);
  // }

  treeClick(e){
    this.selectedNode = e.node;
  }

  treeNodeExpand(e){
    this.expandNode = e.node;
    this.getTables(this.expandNode.key);
  }

  searchValueChange(e){

  }

  searchChange(e){
    this.searchInput$.next(e);
  }

  createAngularModel(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    const prefix:string = this.preSuffixAngularModelForm.value['prefix'];
    const suffix:string = this.preSuffixAngularModelForm.value['suffix'];

    this.angularModel = this.mysqlService.createAngularModel(node.key,prefix,suffix);
    this.drawerVisible_angularModel = false;
  }


  clickSwitcher(){
    this.msg(this.hideUnMatched + '');
  }

  close(){
    this.drawerVisible = false;
  }


  // 生成 Mybatis 批量插入的 SQL 语句
  createMybatisSaveBatch(upperAttribute:boolean){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createMybatisSaveBatch(node.key,!upperAttribute);
  }

  // 获取树形结构中被选中的第一个节点的 key
  // 其应该等于 mysqlService 的 rs 数组中一行的字段 auto_key
  getSelectedNodeKey():number{
    let node = this.tree.getSelectedNodeList()[0];
    return <number><unknown>node.key;
  }


  // 生成 Mybatis 单行数据的新增/修改 SQL 语句
  // 触发服务中的具体实现的方法：save_packagePath_createMybatisSaveOne
  createMybatisSaveOne(){
    this.popOverVisible_createMybatisSaveOne = true;
  }

  // 创建 Mybatis - selectAll 方法
  createMybatisSelectAll(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createMybatisSelectAll(node.key);
  }

  save_packagePath_createMybatisSaveOne(){
    if( this.packagePath_createMybatisSaveOne.length<=0 ){
      this.msg('包名必须设置！');
      return
    }

    this.popOverVisible_createMybatisSaveOne = false;

    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    console.log('开始调用服务层方法：upperAttribute=' + this.upperAttribute);
    this.angularModel = this.mysqlService.createMybatisSaveOne(node.key,
      this.packagePath_createMybatisSaveOne,this.upperAttribute);

  }


  // 生成 Spring DAO 自定义的三剑客：selectAll、saveOne、saveBatch
  createSpringDao(){
    this.popOverVisible_createSpringDao = true;
  }

  createSpringDaoGo(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createSpringDao(node.key,this.modelName_createSpringDao);
  }

  createSpringController(){
    this.popOverVisible_createSpringController = true;
  }

  createSpringControllerGo(){
    if( this.tree === undefined || this.tree === null ){
      this.msg('左侧树不存在！');
      return
    }

    let node = this.tree.getSelectedNodeList()[0];

    if( node === undefined || node === null ){
      this.msg('没有选中节点！');
      return
    }

    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( origin === undefined || origin === null ){
      this.msg('表名为空！');
      return
    }

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createSpringController(node.key,this.modelName_createSpringController);
  }

  createAngularService(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createAngularService(node.key);
  }


  change_createMybatisSaveOne(e){
    console.log(e);
  }


  // 从远端服务器中获取数据更新本地数据
  refreshLocalData(){
    if( this.dbConfig === undefined || this.dbConfig === null ){
      this.msg('还没有设置连接服务器的参数！');
      return
    }


    this.mysqlService.buildFieldTree(this.dbConfig).subscribe(
      ( res:any[] )=>{
        console.log(res);
        this.treeData = res;
        this.msg('更新完毕！');
      },error=>this.msg('构建树时出错！')
    )

    this.drawerVisible = false;// 关闭抽屉

  }


  createFieldString(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    this.angularModel = this.mysqlService.createFieldString(node.key);
  }


  printEval(){
    let raw:string = '(meter + way) * cy';
    let data = {iid:1,meter:10,way:2,cy:3};
    let arr:{label:string,value:number}[] = [];
    let ret:string = raw;
    for(let attri in data){
      ret = ret.replace(attri,data[attri]);
    }
  }

  // 生成代码模板代码
  createSingleTemplate() {
    this.angularModel = this.mysqlService.createSingleTemplate();
  }

  createSingleController() {
    const tableName: string = this.singleControllerForm.value.tableName;
    const modelName: string = this.singleControllerForm.value.modelName;
    const detailService = this.singleControllerForm.value.detailService;
    const packageName = this.singleControllerForm.value.packageName;
    this.angularModel = this.mysqlService.createSingleController(tableName, modelName, detailService, packageName);
  }

  // 生成 spring 服务接口
  createSrpingService() {
    this.angularModel = this.mysqlService.createSpringService(this.modelName_CreateSpringService);
  }

  // 生成 spring 服务实现类
  createSrpingServiceImpl() {
    this.angularModel = this.mysqlService.createSpringServiceImpl(this.modelName_CreateSpringService);
  }

  // 保存抽屉组件中的表单 - 生成单表类型的控制器
  saveDrawer_SingleControllerParam() {
    this.createSingleController();
    this.visible_SingleControllerForm = false;
  }


  // 关闭抽屉组件
  cancelDrawerEdit() {
    this.visible_SingleControllerForm = false;
  }

  createModuleImports() {
    this.angularModel = this.mysqlService.createModuleImports();
  }


  createSQL_pk2Records() {
    const tableName: string = this.pks2RecordsForm.controls.tableName.value;
    const pkFieldName = this.pks2RecordsForm.controls.pkFieldName.value;
    this.angularModel = this.mysqlService.createSQL_pk2Records(tableName, pkFieldName);
    this.visible_CreateSQL_pks2Records = false;
  }

  // 生成带有前后缀的 Java Model
  saveDrawer_preSuffixJavaModelForm(){
    const prefix:string = this.preSuffixJavaModelForm.value['prefix'];
    const suffix:string = this.preSuffixJavaModelForm.value['suffix'];
    const selectedNodeKey:number = this.getSelectedNodeKey();

    this.mysqlService.createJavaModel(this.dbConfig,selectedNodeKey,prefix,suffix).subscribe(
      ( res:string ) =>{
        this.angularModel = res;
        this.drawerVisible_preSuffixJavaModel = false;
      }
    ),error => this.msg('请求获取表字段时出现异常！')
  }

  saveDrawer_preSuffixAngularModelForm(){
    let node = this.tree.getSelectedNodeList()[0];
    let origin = this.tree.getSelectedNodeList()[0].origin.origin;

    if( !this.mysqlService.isTable(origin) ){
      this.msg('选中节点不是表！');
      return;
    }

    const prefix:string = this.preSuffixAngularModelForm.value['prefix'];
    const suffix:string = this.preSuffixAngularModelForm.value['suffix'];

    this.angularModel = this.mysqlService.createAngularModel(node.key,prefix,suffix);
    this.drawerVisible_angularModel = false;
  }

  //#region 公共模型
  menuGeneralModel() {
    //#region 模板代码
    const ret = `
    // 下面代码所属文件为：src/app/global/model.ts
    export class JsonResult {
    code: number;
    msg: string;
    data: any;

    static getError(msg: string = '验证未通过，操作被中断！'): JsonResult {
        const ret = new JsonResult();
        ret.code = -1;
        ret.msg = msg;
        ret.data = null;

        return ret;
    }

    constructor(data?: any) {
        this.code = 1;
        this.data = data;
    }
  }
  export class ZorroOption {
      label: string;
      value: string;
  }
  /**
   * ng-zorro-antd 表格控件点击列头进行排序时
   * 传递给自定义方法的数据模型
   * 调用方法：<thead (nzSortChange)="sort($event)" nzSingleSort>
   * 参数 $event 的模型即为本模型
   */
  export class NzSort {
      key: string; // 点击的表格列的字段名称
      value: string; // ascend,descend
  }
  /**
   * ng-zorro-antd 表格控件列过滤的下拉数据模型
   */
  export class NzFilterOpts {
      text: string;
      value: string;
  }
  /**
   * 执行过滤的依据：
   * fieldName：过滤的字段
   * opts:string[]：多选过滤依据 - 数组
   */
  export class NzFilterReference{
      fieldName: string;
      opts: any;
  }`;
    //#endregion
    this.angularModel = ret;
  }
  //#endregion

  //#region 数组工具类
  menuGeneralArrayUtils(){
    //#region 模板代码
    const ret = `
  import { Injectable } from '@angular/core';
  import { StringUtilsService } from './string-utils.service';
  
  @Injectable({
    providedIn: 'root'
  })
  export class ArrayutilsService {
  
    constructor(
      private stringUtils:StringUtilsService
    ) { }
  
    //#region 二维数组生成树形结构用到的全局属性
    levels = [];
    treeNodeKeyFieldName = 'auto_key';
    //#endregion
  
    //#region 二维数组生成树形结构
    /**
     * 将二维数组转换为树形结构。将下面SQL语句获得的集合转换为按照：数据库、表名、字段名，分3层的树形结构
     * 实际这里不限制层数，按照第二个参数中数组的长度动态分层，本案例以ng-zorro-antd 的 nzTree 为例制作
     * 如果更换为其他组件，那么修改方法 recursion 中的构建 node 的属性即可
     * @param rs 二维数组
     * @param distFields 按照从上到下分层次的字段构成的字符串数组
     * @param keyFieldName 二维数组中主键字段名称，可唯一确定一行数据
     */
    buildTree(rs:any[],distFields:string[],keyFieldName:string):any[]{
      let i = 0;
      for(i=0;i<distFields.length;i++){
        let ele = [this.buildDistArray(rs,distFields.slice(0,i+1)),distFields.slice(0,i+1)];
        this.levels.push(ele);
      }
  
      if( keyFieldName.length>0 ) this.treeNodeKeyFieldName = keyFieldName;
      return this.recursion(0,this.levels[0][0],this.levels[0][1]);
    }
  
    private recursion(level:number,curLevelArray:any[],distFields:string[]):any[]{
      let nodes = [];
      curLevelArray.forEach(ele => {
        let distField = distFields[distFields.length-1];
        let title = ele[distField];
        let node = {'title':title,'key':ele[this.treeNodeKeyFieldName],'children':[],'isLeaf':false};
        if( level===this.levels.length-1 ) node.isLeaf = true;
  
        let nextLevel = level + 1;
        let childrenNodes = [];
        if(nextLevel<this.levels.length){
          let subArray = this.getSames(this.levels[nextLevel][0],ele,this.levels[level][1]);
          childrenNodes = this.recursion(nextLevel,subArray,this.levels[nextLevel][1]);
        }
        node.children = childrenNodes;
        nodes.push(node);
      });
  
      return nodes;
    }
    //#endregion
  
    /**
     * 检测某个元素是否存在于数组中，存在则返回true
     * @param array 被检测的数组
     * @param ele 被检测的元素
     */
    has(array:any[],ele:any):boolean{
      return array.some((element,index,array)=>{
        return ele === element;
      });
    }
  
    /**
     * 检测数组中是否有类似的元素，检测指定的几个属性的值都相等，则返回true
     * 要求数组中元素的结构和样本对象的结构相同
     * @param array 被检测的数组
     * @param ele 样本对象，带有N个属性
     * @param fields 要核对的N个属性名构成的字符串数组
     */
    hasSame(array:any[],ele:any,fields:string[]):boolean{
      let sample = this.combineAttr2String(ele,fields);
      console.log('样本：' + sample);
      
      return array.some(
        (item,index,array)=>{
          let detected = this.combineAttr2String(item,fields);
          console.log('检测对象：' + detected);
          return sample === detected;
        }
      )
    }
  
    /**
     * 返回在多个属性上一致的记录构成的数组
     * @param array 源数组
     * @param record 样本记录，对象，数组中的单个元素
     * @param fields 属性构成的字符串数组
     */
    getSames(array:any[],record:any,fields:string[]):any[]{
      let ret = [];
      let sample = this.combineAttr2String(record,fields);
      array.forEach(ele => {
        let detected = this.combineAttr2String(ele,fields);
        if( detected === sample ) ret.push(ele);
      });
  
      return ret;
    }
  
    /**
     * 构建在指定的属性上不重复的元素构成的新数组，多个重复的元素中只取第一条
     * @param array 原始数组
     * @param fields 属性名构成的字符串数组
     */
    buildDistArray(array:any[],fields:string[]):any[]{
      let combinArray = [];
      let ret = [];
  
      combinArray.push(this.combineAttr2String(array[0],fields));
      ret.push(array[0]);
  
      array.forEach(ele => {
        let detected = this.combineAttr2String(ele,fields);
  
        let exists = combinArray.some(
          (item,index,array)=>{
            return item === detected;
          }
        )
  
        if(!exists) {
          combinArray.push(detected);
          ret.push(ele);
        }
  
      });
  
      return ret;
    }
  
    /**
     * 返回格式为：attr1=value1,attr2=value2 的字符串
     * @param item 拥有N个属性的对象实例或者数组元素
     * @param fields 要链接的属性名称字符串构成的数组
     */
    combineAttr2String(item:any,fields:string[]){
      let ret = '';
      let i = 0;
      for(i=0;i<fields.length;i++){
        ret = ret + fields[i] + '=' + item[fields[i]] + ',';
      }
      
      let last = ret.substr(ret.length-1,1);
      if( last === ',' ) ret = ret.substr(0,ret.length-1)
      return ret;
    }
  
    /**
     * 便利数组中的对象，将某个属性构建为逗号间隔的字符串
     * @param arr 某类型的对象构成的数组
     * @param attr 对象中的某个属性
     */
    buildAttrValueString<T>(arr:T[],attr:string):string{
      if( !arr ) return '';
      if( !attr ) return '';
  
      let ret:string = '';
      arr.forEach(ele => {
        for(let attri in ele){
          if( attri == attr ) ret = ret + ele[attr] +',';
        }
      });
  
      ret = this.stringUtils.delLastSymbol(ret,',');
      return ret;
    }
  
    replace<T>(arr:T[],index:number,element:T):T[]{
      let ret:T[] = arr.filter( 
        ( item:T,ind:number,a:T[] ) =>{
          return ind !== index;
        }
       )
  
      ret.splice(index,0,element);
      return ret;
    }
  }`
    //#endregion
    this.angularModel = ret;
  }
  //#endregion

  //#region 字符串工具类
  menuGeneralStringUtils(){
    //#region 模板代码
    const ret = `
    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class StringUtilsService {
    
      constructor() { }
    
      /**
       * 多个单词组成的字符串将每个单词的首字母大写后返回
       * 首字母大写，每个间隔符号后的第一个字母大写
       * @param val 有固定间隔符号的多个单词构成的字符串
       * @param delimiter 间隔符号，可选参数，默认下划线
       */
      toUpperWords(val:string,delimiter?:string):string{
        // 默认为下划线
        if( delimiter === undefined || delimiter === null || delimiter.length <=0 )
          delimiter = '_';
    
        if( val === undefined || val === null || val.length <=0 )
          return '';
    
        let strArr:string[] = val.split(delimiter);
        if( strArr.length <=0 ) return '';
    
        let ret = '';
        strArr.forEach(ele => {
          ret = ret + ele.charAt(0).toUpperCase() + ele.slice(1);
        })
    
        return ret;
      }
    
      /**
       * 将MySQL表字段（带有下划线作为间隔符号）转换为 Java POJO类属性
       * 首字母小写，每个间隔符号后的第一个字母大写
       * @param val MySQL表字段，带有下划线作为单词间隔符号
       * @param delimiter 可选传入，默认为下划线
       */
      toPOJOAttribute(val:string,delimiter?:string):string{
        let ret = this.toUpperWords(val,delimiter);
        ret = ret.charAt(0).toLowerCase() + ret.slice(1);
        return ret;
      }
    
      /**
       * 如果字符串最后一个字符是间隔符号，那么将其删除
       * @param val 字符串
       * @param symbol 间隔符号
       */
      delLastSymbol(val:string,symbol:string):string{
        if( !val ) return '';
        if( !symbol ) return val;
    
        const last:string = val.substr(val.length-1,1);
        if( last === symbol ) return val.substr(0,val.length-1);
        return val;
      }
    }
`;
    //#endregion
    this.angularModel = ret;
  }
  //#endregion


  // 创建带有前后缀的 Mybatis Result Map
  saveDrawer_preSuffixMybatisResultMapForm(){
    const nodeKey:number = this.getSelectedNodeKey();
    const prefix:string = this.preSuffixMybatisResultMapForm.value['prefix'];
    const suffix:string = this.preSuffixMybatisResultMapForm.value['suffix'];

    this.mysqlService.createMybatisResultMap(this.dbConfig,nodeKey,prefix,suffix).subscribe(
      ( res:string ) =>{
        this.angularModel = res;
        this.drawerVisible_MybatisResultMap = false;
      }
    ),error => this.msg('请求Mybatis Result Map时出现异常！')
  }


  // 生成序时表服务类
  saveDrawer_chroRptService(){
    const jControllerName:string = this.chroRptServiceForm.value['jControllerName'];
    const mainTableName:string = this.chroRptServiceForm.value['mainTableName'];
    const detailTableName:string = this.chroRptServiceForm.value['detailTableName'];
    const billName:string = this.chroRptServiceForm.value['billName'];
    const mainPrefix:string = this.chroRptServiceForm.value['mainPrefix'];
    const detailPrefix:string = this.chroRptServiceForm.value['detailPrefix'];

    this.angularModel = this.mysqlService.createChroRptService(jControllerName,mainTableName,
      detailTableName,billName,mainPrefix,detailPrefix);

    this.drawerVisible_chroRptService = false;
  }

  // 生成单据序时表控制器代码
  saveDrawer_chroRptControllerForm(){
    const serviceName:string = this.chroRptControllerForm.value['serviceName'];
    const billModel:string = this.chroRptControllerForm.value['billModel'];

    this.angularModel = this.mysqlService.createChroRptController(serviceName,billModel);
    this.drawerVisible_chroRptController = false;
  }

  // 生成SQL语句 - 向表 table_style 插入字段样式数据
  saveDrawer_insertTableStyleForm(){
    const dbName:string = this.insertTableStyleForm.value['dbName'];
    const tableName:string = this.insertTableStyleForm.value['tableName'];

    this.angularModel = this.mysqlService.createSQL_insertTableStyle(dbName,tableName);
    this.drawerVisible_insertTableStyle = false;
  }

  createSQL_characterSet(){
    this.angularModel = this.mysqlService.createSQL_characterSet(this.dbNameCharSet);
    this.modalVisible_charSet  = false;
  }

  createSQL_emptyString(){
    this.angularModel = this.mysqlService.createSQL_emptyString(this.dbNameEmptyString);
    this.modalVisible_emptyString = false;
  }


  //#region 自定义彩色消息通知
  msg(content: string) {
    this.pMsgService.add({key: 'custom', severity: 'info', summary: '通知', detail: content});
  }
  //#endregion
}
